#include "wx/wxprec.h"

#ifndef WX_PRECOMP
#include "wx/string.h"
#include "wx/log.h"
#include "wx/intl.h"
#include "wx/frame.h"
#include "wx/window.h"
#include "wx/control.h"
#include "wx/checkbox.h"
#include "wx/radiobut.h"
#include "wx/statbox.h"
#include "wx/textctrl.h"
#include "wx/settings.h"
#include "wx/dialog.h"
#include "wx/msgdlg.h"
#include "wx/statusbr.h"
#include "wx/toolbar.h"
#include "wx/dcclient.h"
#include "wx/scrolbar.h"
#include "wx/layout.h"
#include "wx/sizer.h"
#endif //WX_PRECOMP

#if wxUSE_DRAG_AND_DROP
#include "wx/dnd.h"
#endif // wxUSE_DRAG_AND_DROP

#if wxUSE_HELP
#include "wx/cshelp.h"
#endif // wxUSE_HELP

#if wxUSE_TOOLTIPS
#include "wx/tooltip.h"
#endif // wxUSE_TOOLTIPS

#if wxUSE_CARET
#include "wx/caret.h"
#endif // wxUSE_CARET

#if wxUSE_SYSTEM_OPTIONS
#include "wx/sysopt.h"
#endif

#include <gtk/gtkversion.h>
extern const unsigned int gtk_major_version;
extern const unsigned int gtk_minor_version;
extern const unsigned int gtk_micro_version;

#include "wx/platinfo.h"

 wxWindowList wxTopLevelWindows;
int wxWindowBase::ms_lastControlId = -200;

IMPLEMENT_ABSTRACT_CLASS( wxWindowBase, wxEvtHandler )

BEGIN_EVENT_TABLE( wxWindowBase, wxEvtHandler )
  EVT_SYS_COLOUR_CHANGED( wxWindowBase::OnSysColourChanged )
  EVT_INIT_DIALOG( wxWindowBase::OnInitDialog )
  EVT_MIDDLE_DOWN( wxWindowBase::OnMiddleClick )
  EVT_HELP( wxID_ANY, wxWindowBase::OnHelp )
END_EVENT_TABLE()

wxWindowBase::wxWindowBase() {
  // no window yet, no parent nor children
  m_parent = ( wxWindow * )NULL;
  m_windowId = wxID_ANY;
  // no constraints on the minimal window size
  m_minWidth =
    m_maxWidth = wxDefaultCoord;
  m_minHeight =
    m_maxHeight = wxDefaultCoord;
  // invalidiated cache value
  m_bestSizeCache = wxDefaultSize;
  // window are created enabled and visible by default
  m_isShown =
    m_isEnabled = true;
  // the default event handler is just this window
  m_eventHandler = this;
  #if wxUSE_VALIDATORS
  // no validator
  m_windowValidator = ( wxValidator * ) NULL;
  #endif // wxUSE_VALIDATORS
  m_hasBgCol = m_hasFgCol = m_hasFont = false;
  m_inheritBgCol = m_inheritFgCol = m_inheritFont = false;
  // no style bits
  m_exStyle = m_windowStyle = 0;
  m_backgroundStyle = wxBG_STYLE_SYSTEM;
  #if wxUSE_CONSTRAINTS
  // no constraints whatsoever
  m_constraints = ( wxLayoutConstraints * ) NULL;
  m_constraintsInvolvedIn = ( wxWindowList * ) NULL;
  #endif // wxUSE_CONSTRAINTS
  m_windowSizer = ( wxSizer * ) NULL;
  m_containingSizer = ( wxSizer * ) NULL;
  m_autoLayout = false;
  #if wxUSE_DRAG_AND_DROP
  m_dropTarget = ( wxDropTarget * )NULL;
  #endif // wxUSE_DRAG_AND_DROP
  #if wxUSE_TOOLTIPS
  m_tooltip = ( wxToolTip * )NULL;
  #endif // wxUSE_TOOLTIPS
  #if wxUSE_CARET
  m_caret = ( wxCaret * )NULL;
  #endif // wxUSE_CARET
  #if wxUSE_PALETTE
  m_hasCustomPalette = false;
  #endif // wxUSE_PALETTE
  m_virtualSize = wxDefaultSize;
  m_scrollHelper = ( wxScrollHelper * ) NULL;
  m_minVirtualWidth =
    m_maxVirtualWidth = wxDefaultCoord;
  m_minVirtualHeight =
    m_maxVirtualHeight = wxDefaultCoord;
  m_windowVariant = wxWINDOW_VARIANT_NORMAL;
  #if wxUSE_SYSTEM_OPTIONS
  if( wxSystemOptions::HasOption( wxWINDOW_DEFAULT_VARIANT ) ) {
    m_windowVariant = ( wxWindowVariant ) wxSystemOptions::GetOptionInt( wxWINDOW_DEFAULT_VARIANT ) ;
  }
  #endif
  // Whether we're using the current theme for this window (wxGTK only for now)
  m_themeEnabled = false;
  // VZ: this one shouldn't exist...
  m_isBeingDeleted = false;
}

bool wxWindowBase::CreateBase( wxWindowBase *parent, wxWindowID id, const wxPoint & ( pos ), const wxSize & ( size ),
                               long style, const wxValidator& wxVALIDATOR_PARAM( validator ), const wxString& name ) {
  #if wxUSE_STATBOX
  wxASSERT_MSG( !parent || !wxDynamicCast( parent, wxStaticBox ),
                _T( "wxStaticBox can't be used as a window parent!" ) );
  #endif // wxUSE_STATBOX
  wxASSERT_MSG( id == wxID_ANY || ( id >= 0 && id < 32767 ),
                _T( "invalid id value" ) );
  m_windowId = id == wxID_ANY ? NewControlId() : id;
  m_windowStyle = style;
  SetName( name );
  SetParent( parent );
  #if wxUSE_VALIDATORS
  SetValidator( validator );
  #endif
  if( parent && ( parent->GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY ) ) {
    SetExtraStyle( GetExtraStyle() | wxWS_EX_VALIDATE_RECURSIVELY );
  }
  return true;
}

bool wxWindowBase::ToggleWindowStyle( int flag ) {
  wxASSERT_MSG( flag, _T( "flags with 0 value can't be toggled" ) );
  bool rc;
  long style = GetWindowStyleFlag();
  if( style & flag ) {
    style &= ~flag;
    rc = false;
  } else {
    style |= flag;
    rc = true;
  }
  SetWindowStyleFlag( style );
  return rc;
}

wxWindowBase::~wxWindowBase() {
  wxASSERT_MSG( GetCapture() != this, wxT( "attempt to destroy window with mouse capture" ) );
  wxPendingDelete.DeleteObject( this );
  wxTopLevelWindows.DeleteObject( ( wxWindow* )this );
  wxASSERT_MSG( GetChildren().GetCount() == 0, wxT( "children not destroyed" ) );
  if( m_parent ) {
    wxTopLevelWindow *tlw = wxDynamicCast( wxGetTopLevelParent( ( wxWindow* )this ), wxTopLevelWindow );
    if( tlw ) {
      wxWindow* tmpDefaultItem = tlw->GetTmpDefaultItem();
      if( tmpDefaultItem == this ) {
        tlw->SetTmpDefaultItem( NULL );
      } else if( tmpDefaultItem ) {
        tlw->SetTmpDefaultItem( NULL );
        if( tlw->GetDefaultItem() == this ) {
          tlw->SetDefaultItem( NULL );
        }
        tlw->SetTmpDefaultItem( tmpDefaultItem );
      } else if( tlw->GetDefaultItem() == this ) {
        tlw->SetDefaultItem( NULL );
      }
    }
  }
  if( m_parent ) {
    m_parent->RemoveChild( this );
  }
  #if wxUSE_CARET
  delete m_caret;
  #endif // wxUSE_CARET
  #if wxUSE_VALIDATORS
  delete m_windowValidator;
  #endif // wxUSE_VALIDATORS
  #if wxUSE_CONSTRAINTS
  DeleteRelatedConstraints();
  if( m_constraints ) {
    UnsetConstraints( m_constraints );
    delete m_constraints;
    m_constraints = NULL;
  }
  #endif
  if( m_containingSizer ) {
    m_containingSizer->Detach( ( wxWindow* )this );
  }
  delete m_windowSizer;
  #if wxUSE_DRAG_AND_DROP
  delete m_dropTarget;
  #endif
  delete m_tooltip;
  wxHelpProvider *helpProvider = wxHelpProvider::Get();
  if( helpProvider ) {
    helpProvider->RemoveHelp( this );
  }
}

void wxWindowBase::SendDestroyEvent() {
  wxWindowDestroyEvent event;
  event.SetEventObject( this );
  event.SetId( GetId() );
  GetEventHandler()->ProcessEvent( event );
}

bool wxWindowBase::Destroy() {
  delete this;
  return true;
}

bool wxWindowBase::Close( bool force ) {
  wxCloseEvent event( wxEVT_CLOSE_WINDOW, m_windowId );
  event.SetEventObject( this );
  event.SetCanVeto( !force );
  return GetEventHandler()->ProcessEvent( event ) && !event.GetVeto();
}

bool wxWindowBase::DestroyChildren() {
  wxWindowList::compatibility_iterator node;
  for( ;; ) {
    node = GetChildren().GetFirst();
    if( !node ) {
      break;
    }
    wxWindow *child = node->GetData();
    delete child;
    wxASSERT_MSG( !GetChildren().Find( child ), wxT( "child didn't remove itself using RemoveChild()" ) );
  }
  return true;
}

void wxWindowBase::DoCentre( int dir ) {
  wxCHECK_RET( !( dir & wxCENTRE_ON_SCREEN ) && GetParent(), _T( "this method only implements centering child windows" ) );
  SetSize( GetRect().CentreIn( GetParent()->GetClientSize(), dir ) );
}

void wxWindowBase::Fit() {
  if( !GetChildren().empty() ) {
    SetSize( GetBestSize() );
  }
}

void wxWindowBase::FitInside() {
  if( GetChildren().GetCount() > 0 ) {
    SetVirtualSize( GetBestVirtualSize() );
  }
}

void wxWindowBase::InvalidateBestSize() {
  m_bestSizeCache = wxDefaultSize;
  if( m_parent && !IsTopLevel() ) {
    m_parent->InvalidateBestSize();
  }
}

wxSize wxWindowBase::DoGetBestSize() const {
  wxSize best;
  if( m_windowSizer ) {
    wxSize minSize = m_windowSizer->GetMinSize();
    wxSize size( GetSize() );
    wxSize clientSize( GetClientSize() );
    wxSize minWindowSize( minSize.x + size.x - clientSize.x, minSize.y + size.y - clientSize.y );
    best = GetWindowSizeForVirtualSize( minWindowSize );
    return best;
  } else if( m_constraints ) {
    wxConstCast( this, wxWindowBase )->SatisfyConstraints();
    int maxX = 0, maxY = 0;
    for( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); node; node = node->GetNext() ) {
      wxLayoutConstraints *c = node->GetData()->GetConstraints();
      if( !c ) {
        continue;
      }
      int x = c->right.GetValue(), y = c->bottom.GetValue();
      if( x > maxX ) {
        maxX = x;
      }
      if( y > maxY ) {
        maxY = y;
      }
    }
    best = wxSize( maxX, maxY );
  }  else if( !GetChildren().empty() ) {
    int maxX = 0,
        maxY = 0;
    for( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
         node;
         node = node->GetNext() ) {
      wxWindow *win = node->GetData();
      if( win->IsTopLevel() || !win->IsShown() || wxDynamicCast( win, wxStatusBar ) ) {
        continue;
      }
      int wx, wy, ww, wh;
      win->GetPosition( &wx, &wy );
      if( wx == wxDefaultCoord ) {
        wx = 0;
      }
      if( wy == wxDefaultCoord ) {
        wy = 0;
      }
      win->GetSize( &ww, &wh );
      if( wx + ww > maxX ) {
        maxX = wx + ww;
      }
      if( wy + wh > maxY ) {
        maxY = wy + wh;
      }
    }
    best = wxSize( maxX, maxY );
  } else {
    wxSize size = GetMinSize();
    if( !size.IsFullySpecified() ) {
      size.SetDefaults( GetSize() );
      wxConstCast( this, wxWindowBase )->SetMinSize( size );
    }
    return size;
  }
  wxSize diff = GetSize() - GetClientSize();
  best.x += wxMax( 0, diff.x );
  best.y += wxMax( 0, diff.y );
  return best;
}

static int wxGetMetricOrDefault( wxSystemMetric what ) {
  int rc = wxSystemSettings::GetMetric( what );
  if( rc == -1 ) {
    switch( what ) {
      case wxSYS_BORDER_X:
      case wxSYS_BORDER_Y:
        rc = 1;
        break;
      case wxSYS_EDGE_X:
      case wxSYS_EDGE_Y:
        rc = 2;
        break;
      default:
        wxFAIL_MSG( _T( "unexpected wxGetMetricOrDefault() argument" ) );
        rc = 0;
    }
  }
  return rc;
}

wxSize wxWindowBase::GetWindowBorderSize() const {
  wxSize size;
  switch( GetBorder() ) {
    case wxBORDER_NONE:
      break;
    case wxBORDER_SIMPLE:
    case wxBORDER_STATIC:
      size.x = wxGetMetricOrDefault( wxSYS_BORDER_X );
      size.y = wxGetMetricOrDefault( wxSYS_BORDER_Y );
      break;
    case wxBORDER_SUNKEN:
    case wxBORDER_RAISED:
      size.x = wxMax( wxGetMetricOrDefault( wxSYS_EDGE_X ), wxGetMetricOrDefault( wxSYS_BORDER_X ) );
      size.y = wxMax( wxGetMetricOrDefault( wxSYS_EDGE_Y ), wxGetMetricOrDefault( wxSYS_BORDER_Y ) );
      break;
    case wxBORDER_DOUBLE:
      size.x = wxGetMetricOrDefault( wxSYS_EDGE_X ) + wxGetMetricOrDefault( wxSYS_BORDER_X );
      size.y = wxGetMetricOrDefault( wxSYS_EDGE_Y ) + wxGetMetricOrDefault( wxSYS_BORDER_Y );
      break;
    default:
      wxFAIL_MSG( _T( "Unknown border style." ) );
      break;
  }
  return size * 2;
}

wxSize wxWindowBase::GetEffectiveMinSize() const {
  wxSize min = GetMinSize();
  if( min.x == wxDefaultCoord || min.y == wxDefaultCoord ) {
    wxSize best = GetBestSize();
    if( min.x == wxDefaultCoord ) {
      min.x =  best.x;
    }
    if( min.y == wxDefaultCoord ) {
      min.y =  best.y;
    }
  }
  return min;
}

void wxWindowBase::SetInitialSize( const wxSize& size ) {
  SetMinSize( size );
  wxSize best = GetEffectiveMinSize();
  if( GetSize() != best ) {
    SetSize( best );
  }
}

wxPoint wxWindowBase::GetClientAreaOrigin() const {
  return wxPoint( 0, 0 );
}

wxSize wxWindowBase::ClientToWindowSize( const wxSize& size ) const {
  const wxSize diff( GetSize() - GetClientSize() );
  return wxSize( size.x == -1 ? -1 : size.x + diff.x, size.y == -1 ? -1 : size.y + diff.y );
}

wxSize wxWindowBase::WindowToClientSize( const wxSize& size ) const {
  const wxSize diff( GetSize() - GetClientSize() );
  return wxSize( size.x == -1 ? -1 : size.x - diff.x, size.y == -1 ? -1 : size.y - diff.y );
}

void wxWindowBase::SetWindowVariant( wxWindowVariant variant ) {
  if( m_windowVariant != variant ) {
    m_windowVariant = variant;
    DoSetWindowVariant( variant );
  }
}

void wxWindowBase::DoSetWindowVariant( wxWindowVariant variant ) {
  wxFont font = GetFont();
  int size = font.GetPointSize();
  switch( variant ) {
    case wxWINDOW_VARIANT_NORMAL:
      break;
    case wxWINDOW_VARIANT_SMALL:
      size *= 3;
      size /= 4;
      break;
    case wxWINDOW_VARIANT_MINI:
      size *= 2;
      size /= 3;
      break;
    case wxWINDOW_VARIANT_LARGE:
      size *= 5;
      size /= 4;
      break;
    default:
      wxFAIL_MSG( _T( "unexpected window variant" ) );
      break;
  }
  font.SetPointSize( size );
  SetFont( font );
}

void wxWindowBase::DoSetSizeHints( int minW, int minH, int maxW, int maxH, int ( incW ), int ( incH ) ) {
  wxCHECK_RET( ( minW == wxDefaultCoord || maxW == wxDefaultCoord || minW <= maxW ) &&
               ( minH == wxDefaultCoord || maxH == wxDefaultCoord || minH <= maxH ),
               _T( "min width/height must be less than max width/height!" ) );
  m_minWidth = minW;
  m_maxWidth = maxW;
  m_minHeight = minH;
  m_maxHeight = maxH;
}


void wxWindowBase::SetVirtualSizeHints( int minW, int minH, int maxW, int maxH ) {
  m_minVirtualWidth = minW;
  m_maxVirtualWidth = maxW;
  m_minVirtualHeight = minH;
  m_maxVirtualHeight = maxH;
}

void wxWindowBase::DoSetVirtualSize( int x, int y ) {
  if( m_minVirtualWidth != wxDefaultCoord && m_minVirtualWidth > x ) {
    x = m_minVirtualWidth;
  }
  if( m_maxVirtualWidth != wxDefaultCoord && m_maxVirtualWidth < x ) {
    x = m_maxVirtualWidth;
  }
  if( m_minVirtualHeight != wxDefaultCoord && m_minVirtualHeight > y ) {
    y = m_minVirtualHeight;
  }
  if( m_maxVirtualHeight != wxDefaultCoord && m_maxVirtualHeight < y ) {
    y = m_maxVirtualHeight;
  }
  m_virtualSize = wxSize( x, y );
}

wxSize wxWindowBase::DoGetVirtualSize() const {
  wxSize size = GetClientSize();
  if( m_virtualSize.x > size.x ) {
    size.x = m_virtualSize.x;
  }
  if( m_virtualSize.y >= size.y ) {
    size.y = m_virtualSize.y;
  }
  return size;
}

void wxWindowBase::DoGetScreenPosition( int *x, int *y ) const {
  if( x ) {
    *x = 0;
  }
  if( y ) {
    *y = 0;
  }
  ClientToScreen( x, y );
}

bool wxWindowBase::Show( bool show ) {
  if( show != m_isShown ) {
    m_isShown = show;
    return true;
  } else {
    return false;
  }
}

bool wxWindowBase::Enable( bool enable ) {
  if( enable != m_isEnabled ) {
    m_isEnabled = enable;
    return true;
  } else {
    return false;
  }
}

bool wxWindowBase::IsShownOnScreen() const {
  return IsShown() && ( IsTopLevel() || !GetParent() || GetParent()->IsShownOnScreen() );
}

bool wxWindowBase::IsTopLevel() const {
  return false;
}

void wxWindowBase::AddChild( wxWindowBase *child ) {
  wxCHECK_RET( child, wxT( "can't add a NULL child" ) );
  wxASSERT_MSG( !GetChildren().Find( ( wxWindow* )child ), _T( "AddChild() called twice" ) );
  GetChildren().Append( ( wxWindow* )child );
  child->SetParent( this );
}

void wxWindowBase::RemoveChild( wxWindowBase *child ) {
  wxCHECK_RET( child, wxT( "can't remove a NULL child" ) );
  GetChildren().DeleteObject( ( wxWindow * )child );
  child->SetParent( NULL );
}

bool wxWindowBase::Reparent( wxWindowBase *newParent ) {
  wxWindow *oldParent = GetParent();
  if( newParent == oldParent ) {
    return false;
  }
  if( oldParent ) {
    oldParent->RemoveChild( this );
  } else {
    wxTopLevelWindows.DeleteObject( ( wxWindow * )this );
  }
  if( newParent ) {
    newParent->AddChild( this );
  } else
  { wxTopLevelWindows.Append( ( wxWindow * )this ); }
  return true;
}

void wxWindowBase::PushEventHandler( wxEvtHandler *handler ) {
  wxEvtHandler *handlerOld = GetEventHandler();
  handler->SetNextHandler( handlerOld );
  if( handlerOld ) {
    GetEventHandler()->SetPreviousHandler( handler );
  }
  SetEventHandler( handler );
}

wxEvtHandler *wxWindowBase::PopEventHandler( bool deleteHandler ) {
  wxEvtHandler *handlerA = GetEventHandler();
  if( handlerA ) {
    wxEvtHandler *handlerB = handlerA->GetNextHandler();
    handlerA->SetNextHandler( ( wxEvtHandler * )NULL );
    if( handlerB ) {
      handlerB->SetPreviousHandler( ( wxEvtHandler * )NULL );
    }
    SetEventHandler( handlerB );
    if( deleteHandler ) {
      delete handlerA;
      handlerA = ( wxEvtHandler * )NULL;
    }
  }
  return handlerA;
}

bool wxWindowBase::RemoveEventHandler( wxEvtHandler *handler ) {
  wxCHECK_MSG( handler, false, _T( "RemoveEventHandler(NULL) called" ) );
  wxEvtHandler *handlerPrev = NULL,
                *handlerCur = GetEventHandler();
  while( handlerCur ) {
    wxEvtHandler *handlerNext = handlerCur->GetNextHandler();
    if( handlerCur == handler ) {
      if( handlerPrev ) {
        handlerPrev->SetNextHandler( handlerNext );
      } else
      { SetEventHandler( handlerNext ); }
      if( handlerNext ) {
        handlerNext->SetPreviousHandler( handlerPrev );
      }
      handler->SetNextHandler( NULL );
      handler->SetPreviousHandler( NULL );
      return true;
    }
    handlerPrev = handlerCur;
    handlerCur = handlerNext;
  }
  wxFAIL_MSG( _T( "where has the event handler gone?" ) );
  return false;
}

void wxWindowBase::InheritAttributes() {
  const wxWindowBase * const parent = GetParent();
  if( !parent ) {
    return;
  }
  if( parent->m_inheritFont && !m_hasFont ) {
    SetFont( parent->GetFont() );
  }
  if( ShouldInheritColours() ) {
    if( parent->m_inheritFgCol && !m_hasFgCol ) {
      SetForegroundColour( parent->GetForegroundColour() );
    }
  }
}

wxVisualAttributes
wxWindowBase::GetClassDefaultAttributes( wxWindowVariant( variant ) ) {
  wxVisualAttributes attrs;
  attrs.font = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );
  attrs.colFg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT );
  #if defined(__WXWINCE__) && (defined(__SMARTPHONE__) || defined(__POCKETPC__))
  attrs.colBg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW );
  #else
  attrs.colBg = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
  #endif
  return attrs;
}

wxColour wxWindowBase::GetBackgroundColour() const {
  if( !m_backgroundColour.Ok() ) {
    wxASSERT_MSG( !m_hasBgCol, _T( "we have invalid explicit bg colour?" ) );
    wxColour colBg = GetDefaultAttributes().colBg;
    if( !colBg.Ok() ) {
      colBg = GetClassDefaultAttributes().colBg;
    }
    return colBg;
  } else {
    return m_backgroundColour;
  }
}

wxColour wxWindowBase::GetForegroundColour() const {
  if( !m_hasFgCol && !m_foregroundColour.Ok() ) {
    wxASSERT_MSG( !m_hasFgCol, _T( "we have invalid explicit fg colour?" ) );
    wxColour colFg = GetDefaultAttributes().colFg;
    if( !colFg.Ok() ) {
      colFg = GetClassDefaultAttributes().colFg;
    }
    return colFg;
  } else {
    return m_foregroundColour;
  }
}

bool wxWindowBase::SetBackgroundColour( const wxColour &colour ) {
  if( colour == m_backgroundColour ) {
    return false;
  }
  m_hasBgCol = colour.Ok();
  if( m_backgroundStyle != wxBG_STYLE_CUSTOM ) {
    m_backgroundStyle = m_hasBgCol ? wxBG_STYLE_COLOUR : wxBG_STYLE_SYSTEM;
  }
  m_inheritBgCol = m_hasBgCol;
  m_backgroundColour = colour;
  SetThemeEnabled( !m_hasBgCol && !m_foregroundColour.Ok() );
  return true;
}

bool wxWindowBase::SetForegroundColour( const wxColour &colour ) {
  if( colour == m_foregroundColour ) {
    return false;
  }
  m_hasFgCol = colour.Ok();
  m_inheritFgCol = m_hasFgCol;
  m_foregroundColour = colour;
  SetThemeEnabled( !m_hasFgCol && !m_backgroundColour.Ok() );
  return true;
}

bool wxWindowBase::SetCursor( const wxCursor& cursor ) {
  if( m_cursor.IsSameAs( cursor ) ) {
    return false;
  }
  m_cursor = cursor;
  return true;
}

wxFont wxWindowBase::GetFont() const {
  // logic is the same as in GetBackgroundColour()
  if( !m_font.Ok() ) {
    wxASSERT_MSG( !m_hasFont, _T( "we have invalid explicit font?" ) );
    wxFont font = GetDefaultAttributes().font;
    if( !font.Ok() ) {
      font = GetClassDefaultAttributes().font;
    }
    return font;
  } else
  { return m_font; }
}

bool wxWindowBase::SetFont( const wxFont& font ) {
  if( font == m_font ) {
    // no change
    return false;
  }
  m_font = font;
  m_hasFont = font.Ok();
  m_inheritFont = m_hasFont;
  InvalidateBestSize();
  return true;
}

void wxWindowBase::SetPalette( const wxPalette& pal ) {
  m_hasCustomPalette = true;
  m_palette = pal;
  // VZ: can anyone explain me what do we do here?
  wxWindowDC d( ( wxWindow * ) this );
  d.SetPalette( pal );
}

wxWindow *wxWindowBase::GetAncestorWithCustomPalette() const {
  wxWindow *win = ( wxWindow * )this;
  while( win && !win->HasCustomPalette() ) {
    win = win->GetParent();
  }
  return win;
}

void wxWindowBase::SetCaret( wxCaret *caret ) {
  if( m_caret ) {
    delete m_caret;
  }
  m_caret = caret;
  if( m_caret ) {
    wxASSERT_MSG( m_caret->GetWindow() == this, wxT( "caret should be created associated to this window" ) );
  }
}

void wxWindowBase::SetValidator( const wxValidator& validator ) {
  if( m_windowValidator ) {
    delete m_windowValidator;
  }
  m_windowValidator = ( wxValidator * )validator.Clone();
  if( m_windowValidator ) {
    m_windowValidator->SetWindow( this );
  }
}

wxRect wxWindowBase::GetUpdateClientRect() const {
  wxRegion rgnUpdate = GetUpdateRegion();
  rgnUpdate.Intersect( GetClientRect() );
  wxRect rectUpdate = rgnUpdate.GetBox();
  wxPoint ptOrigin = GetClientAreaOrigin();
  rectUpdate.x -= ptOrigin.x;
  rectUpdate.y -= ptOrigin.y;
  return rectUpdate;
}

bool wxWindowBase::DoIsExposed( int x, int y ) const {
  return m_updateRegion.Contains( x, y ) != wxOutRegion;
}

bool wxWindowBase::DoIsExposed( int x, int y, int w, int h ) const {
  return m_updateRegion.Contains( x, y, w, h ) != wxOutRegion;
}

void wxWindowBase::ClearBackground() {
}

wxWindow *wxWindowBase::FindWindow( long id ) const {
  if( id == m_windowId ) {
    return ( wxWindow * )this;
  }
  wxWindowBase *res = ( wxWindow * )NULL;
  wxWindowList::compatibility_iterator node;
  for( node = m_children.GetFirst(); node && !res; node = node->GetNext() ) {
    wxWindowBase *child = node->GetData();
    res = child->FindWindow( id );
  }
  return ( wxWindow * )res;
}

wxWindow *wxWindowBase::FindWindow( const wxString& name ) const {
  if( name == m_windowName ) {
    return ( wxWindow * )this;
  }
  wxWindowBase *res = ( wxWindow * )NULL;
  wxWindowList::compatibility_iterator node;
  for( node = m_children.GetFirst(); node && !res; node = node->GetNext() ) {
    wxWindow *child = node->GetData();
    res = child->FindWindow( name );
  }
  return ( wxWindow * )res;
}

typedef bool ( *wxFindWindowCmp )( const wxWindow *win, const wxString& label, long id );

static bool wxFindWindowCmpLabels( const wxWindow *win, const wxString& label, long ( id ) ) {
  return win->GetLabel() == label;
}

static bool wxFindWindowCmpNames( const wxWindow *win, const wxString& label, long ( id ) ) {
  return win->GetName() == label;
}

static bool wxFindWindowCmpIds( const wxWindow *win, const wxString & ( label ), long id ) {
  return win->GetId() == id;
}

static wxWindow *wxFindWindowRecursively( const wxWindow *parent, const wxString& label, long id, wxFindWindowCmp cmp ) {
  if( parent ) {
    // see if this is the one we're looking for
    if( ( *cmp )( parent, label, id ) ) {
      return ( wxWindow * )parent;
    }
    // It wasn't, so check all its children
    for( wxWindowList::compatibility_iterator node = parent->GetChildren().GetFirst();
         node;
         node = node->GetNext() ) {
      // recursively check each child
      wxWindow *win = ( wxWindow * )node->GetData();
      wxWindow *retwin = wxFindWindowRecursively( win, label, id, cmp );
      if( retwin ) {
        return retwin;
      }
    }
  }
  // Not found
  return NULL;
}

static wxWindow *wxFindWindowHelper( const wxWindow *parent, const wxString& label, long id, wxFindWindowCmp cmp ) {
  if( parent ) {
    return wxFindWindowRecursively( parent, label, id, cmp );
  }
  for( wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() ) {
    wxWindow *win = node->GetData();
    wxWindow *retwin = wxFindWindowRecursively( win, label, id, cmp );
    if( retwin ) {
      return retwin;
    }
  }
  return NULL;
}

wxWindow * wxWindowBase::FindWindowByLabel( const wxString& title, const wxWindow *parent ) {
  return wxFindWindowHelper( parent, title, 0, wxFindWindowCmpLabels );
}

wxWindow * wxWindowBase::FindWindowByName( const wxString& title, const wxWindow *parent ) {
  wxWindow *win = wxFindWindowHelper( parent, title, 0, wxFindWindowCmpNames );
  if( !win ) {
    win = FindWindowByLabel( title, parent );
  }
  return win;
}

wxWindow * wxWindowBase::FindWindowById( long id, const wxWindow* parent ) {
  return wxFindWindowHelper( parent, wxEmptyString, id, wxFindWindowCmpIds );
}

void wxWindowBase::MakeModal( bool modal ) {
  if( IsTopLevel() ) {
    wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst();
    while( node ) {
      wxWindow *win = node->GetData();
      if( win != this ) {
        win->Enable( !modal );
      }
      node = node->GetNext();
    }
  }
}

bool wxWindowBase::Validate() {
  #if wxUSE_VALIDATORS
  bool recurse = ( GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY ) != 0;
  wxWindowList::compatibility_iterator node;
  for( node = m_children.GetFirst(); node; node = node->GetNext() ) {
    wxWindowBase *child = node->GetData();
    wxValidator *validator = child->GetValidator();
    if( validator && !validator->Validate( ( wxWindow * )this ) ) {
      return false;
    }
    if( recurse && !child->Validate() ) {
      return false;
    }
  }
  #endif // wxUSE_VALIDATORS
  return true;
}

bool wxWindowBase::TransferDataToWindow() {
  #if wxUSE_VALIDATORS
  bool recurse = ( GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY ) != 0;
  wxWindowList::compatibility_iterator node;
  for( node = m_children.GetFirst(); node; node = node->GetNext() ) {
    wxWindowBase *child = node->GetData();
    wxValidator *validator = child->GetValidator();
    if( validator && !validator->TransferToWindow() ) {
      wxLogWarning( _( "Could not transfer data to window" ) );
      #if wxUSE_LOG
      wxLog::FlushActive();
      #endif // wxUSE_LOG
      return false;
    }
    if( recurse ) {
      if( !child->TransferDataToWindow() ) {
        return false;
      }
    }
  }
  #endif // wxUSE_VALIDATORS
  return true;
}

bool wxWindowBase::TransferDataFromWindow() {
  #if wxUSE_VALIDATORS
  bool recurse = ( GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY ) != 0;
  wxWindowList::compatibility_iterator node;
  for( node = m_children.GetFirst(); node; node = node->GetNext() ) {
    wxWindow *child = node->GetData();
    wxValidator *validator = child->GetValidator();
    if( validator && !validator->TransferFromWindow() ) {
      return false;
    }
    if( recurse ) {
      if( !child->TransferDataFromWindow() ) {
        // warning already given
        return false;
      }
    }
  }
  #endif // wxUSE_VALIDATORS
  return true;
}

void wxWindowBase::InitDialog() {
  wxInitDialogEvent event( GetId() );
  event.SetEventObject( this );
  GetEventHandler()->ProcessEvent( event );
}

void wxWindowBase::SetHelpText( const wxString& text ) {
  wxHelpProvider *helpProvider = wxHelpProvider::Get();
  if( helpProvider ) {
    helpProvider->AddHelp( this, text );
  }
}

void wxWindowBase::SetHelpTextForId( const wxString& text ) {
  wxHelpProvider *helpProvider = wxHelpProvider::Get();
  if( helpProvider ) {
    helpProvider->AddHelp( GetId(), text );
  }
}

wxString wxWindowBase::GetHelpTextAtPoint( const wxPoint & ( pt ), wxHelpEvent::Origin( origin ) ) const {
  wxString text;
  wxHelpProvider *helpProvider = wxHelpProvider::Get();
  if( helpProvider ) {
    text = helpProvider->GetHelp( this );
  }
  return text;
}

void wxWindowBase::OnHelp( wxHelpEvent& event ) {
  wxHelpProvider *helpProvider = wxHelpProvider::Get();
  if( helpProvider ) {
    wxPoint pos = event.GetPosition();
    const wxHelpEvent::Origin origin = event.GetOrigin();
    if( origin == wxHelpEvent::Origin_Keyboard ) {
      const wxRect rectClient = GetClientRect();
      if( !rectClient.Contains( ScreenToClient( pos ) ) ) {
        pos = ClientToScreen( wxPoint( 2 * GetCharWidth(), rectClient.height + GetCharHeight() ) );
      }
    }
    if( helpProvider->ShowHelpAtPoint( this, pos, origin ) ) {
      return;
    }
  }
  event.Skip();
}

void wxWindowBase::SetToolTip( const wxString &tip ) {
  if( m_tooltip ) {
    m_tooltip->SetTip( tip );
  } else
  { SetToolTip( new wxToolTip( tip ) ); }
}

void wxWindowBase::DoSetToolTip( wxToolTip *tooltip ) {
  if( m_tooltip != tooltip ) {
    if( m_tooltip ) {
      delete m_tooltip;
    }
    m_tooltip = tooltip;
  }
}

void wxWindowBase::SetConstraints( wxLayoutConstraints *constraints ) {
  if( m_constraints ) {
    UnsetConstraints( m_constraints );
    delete m_constraints;
  }
  m_constraints = constraints;
  if( m_constraints ) {
    if( m_constraints->left.GetOtherWindow() && ( m_constraints->left.GetOtherWindow() != this ) ) {
      m_constraints->left.GetOtherWindow()->AddConstraintReference( this );
    }
    if( m_constraints->top.GetOtherWindow() && ( m_constraints->top.GetOtherWindow() != this ) ) {
      m_constraints->top.GetOtherWindow()->AddConstraintReference( this );
    }
    if( m_constraints->right.GetOtherWindow() && ( m_constraints->right.GetOtherWindow() != this ) ) {
      m_constraints->right.GetOtherWindow()->AddConstraintReference( this );
    }
    if( m_constraints->bottom.GetOtherWindow() && ( m_constraints->bottom.GetOtherWindow() != this ) ) {
      m_constraints->bottom.GetOtherWindow()->AddConstraintReference( this );
    }
    if( m_constraints->width.GetOtherWindow() && ( m_constraints->width.GetOtherWindow() != this ) ) {
      m_constraints->width.GetOtherWindow()->AddConstraintReference( this );
    }
    if( m_constraints->height.GetOtherWindow() && ( m_constraints->height.GetOtherWindow() != this ) ) {
      m_constraints->height.GetOtherWindow()->AddConstraintReference( this );
    }
    if( m_constraints->centreX.GetOtherWindow() && ( m_constraints->centreX.GetOtherWindow() != this ) ) {
      m_constraints->centreX.GetOtherWindow()->AddConstraintReference( this );
    }
    if( m_constraints->centreY.GetOtherWindow() && ( m_constraints->centreY.GetOtherWindow() != this ) ) {
      m_constraints->centreY.GetOtherWindow()->AddConstraintReference( this );
    }
  }
}

void wxWindowBase::UnsetConstraints( wxLayoutConstraints *c ) {
  if( c ) {
    if( c->left.GetOtherWindow() && ( c->top.GetOtherWindow() != this ) ) {
      c->left.GetOtherWindow()->RemoveConstraintReference( this );
    }
    if( c->top.GetOtherWindow() && ( c->top.GetOtherWindow() != this ) ) {
      c->top.GetOtherWindow()->RemoveConstraintReference( this );
    }
    if( c->right.GetOtherWindow() && ( c->right.GetOtherWindow() != this ) ) {
      c->right.GetOtherWindow()->RemoveConstraintReference( this );
    }
    if( c->bottom.GetOtherWindow() && ( c->bottom.GetOtherWindow() != this ) ) {
      c->bottom.GetOtherWindow()->RemoveConstraintReference( this );
    }
    if( c->width.GetOtherWindow() && ( c->width.GetOtherWindow() != this ) ) {
      c->width.GetOtherWindow()->RemoveConstraintReference( this );
    }
    if( c->height.GetOtherWindow() && ( c->height.GetOtherWindow() != this ) ) {
      c->height.GetOtherWindow()->RemoveConstraintReference( this );
    }
    if( c->centreX.GetOtherWindow() && ( c->centreX.GetOtherWindow() != this ) ) {
      c->centreX.GetOtherWindow()->RemoveConstraintReference( this );
    }
    if( c->centreY.GetOtherWindow() && ( c->centreY.GetOtherWindow() != this ) ) {
      c->centreY.GetOtherWindow()->RemoveConstraintReference( this );
    }
  }
}

void wxWindowBase::AddConstraintReference( wxWindowBase *otherWin ) {
  if( !m_constraintsInvolvedIn ) {
    m_constraintsInvolvedIn = new wxWindowList;
  }
  if( !m_constraintsInvolvedIn->Find( ( wxWindow * )otherWin ) ) {
    m_constraintsInvolvedIn->Append( ( wxWindow * )otherWin );
  }
}

void wxWindowBase::RemoveConstraintReference( wxWindowBase *otherWin ) {
  if( m_constraintsInvolvedIn ) {
    m_constraintsInvolvedIn->DeleteObject( ( wxWindow * )otherWin );
  }
}

void wxWindowBase::DeleteRelatedConstraints() {
  if( m_constraintsInvolvedIn ) {
    wxWindowList::compatibility_iterator node = m_constraintsInvolvedIn->GetFirst();
    while( node ) {
      wxWindow *win = node->GetData();
      wxLayoutConstraints *constr = win->GetConstraints();
      if( constr ) {
        constr->left.ResetIfWin( this );
        constr->top.ResetIfWin( this );
        constr->right.ResetIfWin( this );
        constr->bottom.ResetIfWin( this );
        constr->width.ResetIfWin( this );
        constr->height.ResetIfWin( this );
        constr->centreX.ResetIfWin( this );
        constr->centreY.ResetIfWin( this );
      }
      wxWindowList::compatibility_iterator next = node->GetNext();
      m_constraintsInvolvedIn->Erase( node );
      node = next;
    }
    delete m_constraintsInvolvedIn;
    m_constraintsInvolvedIn = ( wxWindowList * ) NULL;
  }
}

void wxWindowBase::SetSizer( wxSizer *sizer, bool deleteOld ) {
  if( sizer == m_windowSizer ) {
    return;
  }
  if( m_windowSizer ) {
    m_windowSizer->SetContainingWindow( NULL );
    if( deleteOld ) {
      delete m_windowSizer;
    }
  }
  m_windowSizer = sizer;
  if( m_windowSizer ) {
    m_windowSizer->SetContainingWindow( ( wxWindow * )this );
  }
  SetAutoLayout( m_windowSizer != NULL );
}

void wxWindowBase::SetSizerAndFit( wxSizer *sizer, bool deleteOld ) {
  SetSizer( sizer, deleteOld );
  sizer->SetSizeHints( ( wxWindow* ) this );
}


void wxWindowBase::SetContainingSizer( wxSizer* sizer ) {
  wxASSERT_MSG( !sizer || m_containingSizer != sizer, _T( "Adding a window to the same sizer twice?" ) );
  m_containingSizer = sizer;
}

#if wxUSE_CONSTRAINTS

void wxWindowBase::SatisfyConstraints() {
  wxLayoutConstraints *constr = GetConstraints();
  bool wasOk = constr && constr->AreSatisfied();
  ResetConstraints();   // Mark all constraints as unevaluated
  int noChanges = 1;
  if( wasOk ) {
    while( noChanges > 0 ) {
      LayoutPhase1( &noChanges );
    }
  }
  LayoutPhase2( &noChanges );
}

#endif // wxUSE_CONSTRAINTS

bool wxWindowBase::Layout() {
  if( GetSizer() ) {
    int w = 0, h = 0;
    GetVirtualSize( &w, &h );
    GetSizer()->SetDimension( 0, 0, w, h );
  }
  #if wxUSE_CONSTRAINTS
  else {
    SatisfyConstraints(); // Find the right constraints values
    SetConstraintSizes(); // Recursively set the real window sizes
  }
  #endif
  return true;
}

#if wxUSE_CONSTRAINTS

bool wxWindowBase::LayoutPhase1( int *noChanges ) {
  wxLayoutConstraints *constr = GetConstraints();
  return !constr || constr->SatisfyConstraints( this, noChanges );
}

bool wxWindowBase::LayoutPhase2( int *noChanges ) {
  *noChanges = 0;
  DoPhase( 1 );
  DoPhase( 2 );
  return true;
}

bool wxWindowBase::DoPhase( int phase ) {
  wxWindowList succeeded;
  static const int maxIterations = 500;
  for( int noIterations = 0; noIterations < maxIterations; noIterations++ ) {
    int noChanges = 0;
    for( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
         node;
         node = node->GetNext() ) {
      wxWindow *child = node->GetData();
      if( child->IsTopLevel() ) {
        continue;
      }
      if( !child->GetConstraints() || succeeded.Find( child ) ) {
        continue;
      }
      int tempNoChanges = 0;
      bool success = phase == 1 ? child->LayoutPhase1( &tempNoChanges )
                     : child->LayoutPhase2( &tempNoChanges );
      noChanges += tempNoChanges;
      if( success ) {
        succeeded.Append( child );
      }
    }
    if( !noChanges ) {
      break;
    }
  }
  return true;
}

void wxWindowBase::ResetConstraints() {
  wxLayoutConstraints *constr = GetConstraints();
  if( constr ) {
    constr->left.SetDone( false );
    constr->top.SetDone( false );
    constr->right.SetDone( false );
    constr->bottom.SetDone( false );
    constr->width.SetDone( false );
    constr->height.SetDone( false );
    constr->centreX.SetDone( false );
    constr->centreY.SetDone( false );
  }
  wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
  while( node ) {
    wxWindow *win = node->GetData();
    if( !win->IsTopLevel() ) {
      win->ResetConstraints();
    }
    node = node->GetNext();
  }
}

void wxWindowBase::SetConstraintSizes( bool recurse ) {
  wxLayoutConstraints *constr = GetConstraints();
  if( constr && constr->AreSatisfied() ) {
    int x = constr->left.GetValue();
    int y = constr->top.GetValue();
    int w = constr->width.GetValue();
    int h = constr->height.GetValue();
    if( ( constr->width.GetRelationship() != wxAsIs ) ||
        ( constr->height.GetRelationship() != wxAsIs ) ) {
      SetSize( x, y, w, h );
    } else
    { Move( x, y ); }
  } else if( constr ) {
    wxLogDebug( wxT( "Constraints not satisfied for %s named '%s'." ), GetClassInfo()->GetClassName(), GetName().c_str() );
  }
  if( recurse ) {
    wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
    while( node ) {
      wxWindow *win = node->GetData();
      if( !win->IsTopLevel() && win->GetConstraints() ) {
        win->SetConstraintSizes();
      }
      node = node->GetNext();
    }
  }
}

void wxWindowBase::SetSizeConstraint( int x, int y, int w, int h ) {
  wxLayoutConstraints *constr = GetConstraints();
  if( constr ) {
    if( x != wxDefaultCoord ) {
      constr->left.SetValue( x );
      constr->left.SetDone( true );
    }
    if( y != wxDefaultCoord ) {
      constr->top.SetValue( y );
      constr->top.SetDone( true );
    }
    if( w != wxDefaultCoord ) {
      constr->width.SetValue( w );
      constr->width.SetDone( true );
    }
    if( h != wxDefaultCoord ) {
      constr->height.SetValue( h );
      constr->height.SetDone( true );
    }
  }
}

void wxWindowBase::MoveConstraint( int x, int y ) {
  wxLayoutConstraints *constr = GetConstraints();
  if( constr ) {
    if( x != wxDefaultCoord ) {
      constr->left.SetValue( x );
      constr->left.SetDone( true );
    }
    if( y != wxDefaultCoord ) {
      constr->top.SetValue( y );
      constr->top.SetDone( true );
    }
  }
}

void wxWindowBase::GetSizeConstraint( int *w, int *h ) const {
  wxLayoutConstraints *constr = GetConstraints();
  if( constr ) {
    *w = constr->width.GetValue();
    *h = constr->height.GetValue();
  } else
  { GetSize( w, h ); }
}

void wxWindowBase::GetClientSizeConstraint( int *w, int *h ) const {
  wxLayoutConstraints *constr = GetConstraints();
  if( constr ) {
    *w = constr->width.GetValue();
    *h = constr->height.GetValue();
  } else
  { GetClientSize( w, h ); }
}

void wxWindowBase::GetPositionConstraint( int *x, int *y ) const {
  wxLayoutConstraints *constr = GetConstraints();
  if( constr ) {
    *x = constr->left.GetValue();
    *y = constr->top.GetValue();
  } else
  { GetPosition( x, y ); }
}

#endif // wxUSE_CONSTRAINTS

void wxWindowBase::AdjustForParentClientOrigin( int& x, int& y, int sizeFlags ) const {
  if( !IsTopLevel() ) {
    wxWindow *parent = GetParent();
    if( !( sizeFlags & wxSIZE_NO_ADJUSTMENTS ) && parent ) {
      wxPoint pt( parent->GetClientAreaOrigin() );
      x += pt.x;
      y += pt.y;
    }
  }
}

void wxWindowBase::UpdateWindowUI( long flags ) {
  wxUpdateUIEvent event( GetId() );
  event.SetEventObject( this );
  if( GetEventHandler()->ProcessEvent( event ) ) {
    DoUpdateWindowUI( event );
  }
  if( flags & wxUPDATE_UI_RECURSE ) {
    wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
    while( node ) {
      wxWindow* child = ( wxWindow* ) node->GetData();
      child->UpdateWindowUI( flags );
      node = node->GetNext();
    }
  }
}

void wxWindowBase::DoUpdateWindowUI( wxUpdateUIEvent& event ) {
  if( event.GetSetEnabled() ) {
    Enable( event.GetEnabled() );
  }
  if( event.GetSetShown() ) {
    Show( event.GetShown() );
  }
}

wxPoint wxWindowBase::ConvertPixelsToDialog( const wxPoint& pt ) {
  int charWidth = GetCharWidth();
  int charHeight = GetCharHeight();
  wxPoint pt2 = wxDefaultPosition;
  if( pt.x != wxDefaultCoord ) {
    pt2.x = ( int )( ( pt.x * 4 ) / charWidth );
  }
  if( pt.y != wxDefaultCoord ) {
    pt2.y = ( int )( ( pt.y * 8 ) / charHeight );
  }
  return pt2;
}

wxPoint wxWindowBase::ConvertDialogToPixels( const wxPoint& pt ) {
  int charWidth = GetCharWidth();
  int charHeight = GetCharHeight();
  wxPoint pt2 = wxDefaultPosition;
  if( pt.x != wxDefaultCoord ) {
    pt2.x = ( int )( ( pt.x * charWidth ) / 4 );
  }
  if( pt.y != wxDefaultCoord ) {
    pt2.y = ( int )( ( pt.y * charHeight ) / 8 );
  }
  return pt2;
}

void wxWindowBase::OnSysColourChanged( wxSysColourChangedEvent& event ) {
  wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
  while( node ) {
    // Only propagate to non-top-level windows
    wxWindow *win = node->GetData();
    if( !win->IsTopLevel() ) {
      wxSysColourChangedEvent event2;
      event.SetEventObject( win );
      win->GetEventHandler()->ProcessEvent( event2 );
    }
    node = node->GetNext();
  }
  Refresh();
}

void wxWindowBase::OnInitDialog( wxInitDialogEvent & ( event ) ) {
  TransferDataToWindow();
  UpdateWindowUI( wxUPDATE_UI_RECURSE );
}

#ifdef __WXDEBUG__

static void DrawSizers( wxWindowBase *win );

static void DrawBorder( wxWindowBase *win, const wxRect& rect, bool fill = false ) {
  wxClientDC dc( ( wxWindow * )win );
  dc.SetPen( *wxRED_PEN );
  dc.SetBrush( fill ? wxBrush( *wxRED, wxCROSSDIAG_HATCH ) : *wxTRANSPARENT_BRUSH );
  dc.DrawRectangle( rect.Deflate( 1, 1 ) );
}

static void DrawSizer( wxWindowBase *win, wxSizer *sizer ) {
  const wxSizerItemList& items = sizer->GetChildren();
  for( wxSizerItemList::const_iterator i = items.begin(),
       end = items.end();
       i != end;
       ++i ) {
    wxSizerItem *item = *i;
    if( item->IsSizer() ) {
      DrawBorder( win, item->GetRect().Deflate( 2 ) );
      DrawSizer( win, item->GetSizer() );
    } else if( item->IsSpacer() ) {
      DrawBorder( win, item->GetRect().Deflate( 2 ), true );
    } else if( item->IsWindow() ) {
      DrawSizers( item->GetWindow() );
    }
  }
}

static void DrawSizers( wxWindowBase *win ) {
  wxSizer *sizer = win->GetSizer();
  if( sizer ) {
    DrawBorder( win, win->GetClientSize() );
    DrawSizer( win, sizer );
  } else { // no sizer, still recurse into the children
    const wxWindowList& children = win->GetChildren();
    for( wxWindowList::const_iterator i = children.begin(), end = children.end();
         i != end;
         ++i ) {
      DrawSizers( *i );
    }
  }
}

#endif // __WXDEBUG__

void wxWindowBase::OnMiddleClick( wxMouseEvent& event ) {
  if( event.ControlDown() && event.AltDown() ) {
    #ifdef __WXDEBUG__
    if( event.ShiftDown() ) {
      DrawSizers( this );
      return;
    }
    #endif // __WXDEBUG__
    wxString msg;
    msg.Printf( _T( "wxWidgets Library (%s port)\n" )
                _T( "Version %s%s, compiled at %s %s\n" )
                _T( "使用的工具包的运行时版本是 %d.%d.%s\n" )
                _T( "Copyright (c) 1995-2010 wxWidgets team" ),
                wxPlatformInfo::Get().GetPortIdName().c_str(),
                L" (Unicode)", wxEmptyString, __TDATE__, __TTIME__, wxPlatformInfo::Get().GetToolkitMajorVersion(),
                wxPlatformInfo::Get().GetToolkitMinorVersion(),
                wxString::Format( _T( "\nThe compile-time GTK+ version is %d.%d.%d." ), GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION ).c_str()
              );
    wxMessageBox( msg, _T( "wxWidgets information" ), wxICON_INFORMATION | wxOK, ( wxWindow * )this );
  } else {
    event.Skip();
  }
}

void wxWindowListNode::DeleteData() {
  delete( wxWindow * )GetData();
}

wxBorder wxWindowBase::GetBorder( long flags ) const {
  wxBorder border = ( wxBorder )( flags & wxBORDER_MASK );
  if( border == wxBORDER_DEFAULT ) {
    border = GetDefaultBorder();
  }
  return border;
}

wxBorder wxWindowBase::GetDefaultBorder() const {
  return wxBORDER_NONE;
}

wxHitTest wxWindowBase::DoHitTest( wxCoord x, wxCoord y ) const {
  bool outside = x < 0 || y < 0;
  if( !outside ) {
    wxSize size = GetSize();
    outside = x >= size.x || y >= size.y;
  }
  return outside ? wxHT_WINDOW_OUTSIDE : wxHT_WINDOW_INSIDE;
}

struct wxWindowNext {
  wxWindow *win;
  wxWindowNext *next;
} *wxWindowBase::ms_winCaptureNext = NULL;
wxWindow *wxWindowBase::ms_winCaptureCurrent = NULL;
bool wxWindowBase::ms_winCaptureChanging = false;

void wxWindowBase::CaptureMouse() {
  wxLogTrace( _T( "mousecapture" ), _T( "CaptureMouse(%p)" ), wx_static_cast( void*, this ) );
  wxASSERT_MSG( !ms_winCaptureChanging, _T( "recursive CaptureMouse call?" ) );
  ms_winCaptureChanging = true;
  wxWindow *winOld = GetCapture();
  if( winOld ) {
    ( ( wxWindowBase* ) winOld )->DoReleaseMouse();
    wxWindowNext *item = new wxWindowNext;
    item->win = winOld;
    item->next = ms_winCaptureNext;
    ms_winCaptureNext = item;
  }
  DoCaptureMouse();
  ms_winCaptureCurrent = ( wxWindow* )this;
  ms_winCaptureChanging = false;
}

void wxWindowBase::ReleaseMouse() {
  wxLogTrace( _T( "mousecapture" ), _T( "ReleaseMouse(%p)" ), wx_static_cast( void*, this ) );
  wxASSERT_MSG( !ms_winCaptureChanging, _T( "recursive ReleaseMouse call?" ) );
  wxASSERT_MSG( GetCapture() == this, wxT( "attempt to release mouse, but this window hasn't captured it" ) );
  ms_winCaptureChanging = true;
  DoReleaseMouse();
  ms_winCaptureCurrent = NULL;
  if( ms_winCaptureNext ) {
    ( ( wxWindowBase* )ms_winCaptureNext->win )->DoCaptureMouse();
    ms_winCaptureCurrent = ms_winCaptureNext->win;
    wxWindowNext *item = ms_winCaptureNext;
    ms_winCaptureNext = item->next;
    delete item;
  }
  ms_winCaptureChanging = false;
  wxLogTrace( _T( "mousecapture" ),
              ( const wxChar * ) _T( "After ReleaseMouse() mouse is captured by %p" ),
              wx_static_cast( void*, GetCapture() ) );
}

static void DoNotifyWindowAboutCaptureLost( wxWindow *win ) {
  wxMouseCaptureLostEvent event( win->GetId() );
  event.SetEventObject( win );
  if( !win->GetEventHandler()->ProcessEvent( event ) ) {
    wxFAIL_MSG( _T( "window that captured the mouse didn't process wxEVT_MOUSE_CAPTURE_LOST" ) );
  }
}

void wxWindowBase::NotifyCaptureLost() {
  if( ms_winCaptureChanging ) {
    return;
  }
  if( ms_winCaptureCurrent ) {
    DoNotifyWindowAboutCaptureLost( ms_winCaptureCurrent );
    ms_winCaptureCurrent = NULL;
  }
  while( ms_winCaptureNext ) {
    wxWindowNext *item = ms_winCaptureNext;
    ms_winCaptureNext = item->next;
    DoNotifyWindowAboutCaptureLost( item->win );
    delete item;
  }
}

#if wxUSE_HOTKEY

bool
wxWindowBase::RegisterHotKey( int ( hotkeyId ),
                              int ( modifiers ),
                              int ( keycode ) ) {
  // not implemented
  return false;
}

bool wxWindowBase::UnregisterHotKey( int ( hotkeyId ) ) {
  // not implemented
  return false;
}

#endif // wxUSE_HOTKEY

bool wxWindowBase::TryValidator( wxEvent& wxVALIDATOR_PARAM( event ) ) {
  #if wxUSE_VALIDATORS
  // Can only use the validator of the window which
  // is receiving the event
  if( event.GetEventObject() == this ) {
    wxValidator *validator = GetValidator();
    if( validator && validator->ProcessEvent( event ) ) {
      return true;
    }
  }
  #endif // wxUSE_VALIDATORS
  return false;
}

bool wxWindowBase::TryParent( wxEvent& event ) {
  if( event.ShouldPropagate() ) {
    if( !( GetExtraStyle() & wxWS_EX_BLOCK_EVENTS ) ) {
      wxWindow *parent = GetParent();
      if( parent && !parent->IsBeingDeleted() ) {
        wxPropagateOnce propagateOnce( event );
        return parent->GetEventHandler()->ProcessEvent( event );
      }
    }
  }
  return wxEvtHandler::TryParent( event );
}

wxWindow *wxWindowBase::DoGetSibling( MoveKind order ) const {
  wxCHECK_MSG( GetParent(), NULL,
               _T( "GetPrev/NextSibling() don't work for TLWs!" ) );
  wxWindowList& siblings = GetParent()->GetChildren();
  wxWindowList::compatibility_iterator i = siblings.Find( ( wxWindow * )this );
  wxCHECK_MSG( i, NULL, _T( "window not a child of its parent?" ) );
  if( order == MoveBefore ) {
    i = i->GetPrevious();
  } else // MoveAfter
  { i = i->GetNext(); }
  return i ? i->GetData() : NULL;
}

bool wxWindowBase::Navigate( int flags ) {
  wxNavigationKeyEvent eventNav;
  eventNav.SetFlags( flags );
  eventNav.SetEventObject( this );
  if( GetParent()->GetEventHandler()->ProcessEvent( eventNav ) ) {
    return true;
  }
  return false;
}

void wxWindowBase::DoMoveInTabOrder( wxWindow *win, MoveKind move ) {
  wxCHECK_RET( GetParent(),
               _T( "MoveBefore/AfterInTabOrder() don't work for TLWs!" ) );
  if( win == this ) {
    return;
  }
  wxWindowList& siblings = GetParent()->GetChildren();
  wxWindowList::compatibility_iterator i = siblings.Find( win );
  wxCHECK_RET( i, _T( "MoveBefore/AfterInTabOrder(): win is not a sibling" ) );
  wxWindow *self = ( wxWindow * )this;
  siblings.DeleteObject( self );
  if( move == MoveAfter ) {
    i = i->GetNext();
  }
  if( i ) {
    siblings.Insert( i, self );
  } else // MoveAfter and win was the last sibling
  { siblings.Append( self ); }
}

wxWindow* wxWindowBase::FindFocus() {
  wxWindowBase *win = DoFindFocus();
  return win ? win->GetMainWindowOfCompositeControl() : NULL;
}

#if wxUSE_DRAG_AND_DROP && !defined(__WXMSW__)

class wxDragAcceptFilesImplTarget : public wxFileDropTarget {
  public:
    wxDragAcceptFilesImplTarget( wxWindowBase *win ) : m_win( win ) {}

    virtual bool OnDropFiles( wxCoord x, wxCoord y,
                              const wxArrayString& filenames ) {
      wxDropFilesEvent event( wxEVT_DROP_FILES,
                              filenames.size(),
                              wxCArrayString( filenames ).Release() );
      event.SetEventObject( m_win );
      event.m_pos.x = x;
      event.m_pos.y = y;
      return m_win->GetEventHandler()->ProcessEvent( event );
    }

  private:
    wxWindowBase * const m_win;

    DECLARE_NO_COPY_CLASS( wxDragAcceptFilesImplTarget )
};

void wxWindowBase::DragAcceptFiles( bool accept ) {
  if( accept ) {
    wxASSERT_MSG( !GetDropTarget(),
                  _T( "cannot use DragAcceptFiles() and SetDropTarget() together" ) );
    SetDropTarget( new wxDragAcceptFilesImplTarget( this ) );
  } else
  { SetDropTarget( NULL ); }
}

#endif // wxUSE_DRAG_AND_DROP && !defined(__WXMSW__)

wxWindow* wxGetTopLevelParent( wxWindow *win ) {
  while( win && !win->IsTopLevel() ) {
    win = win->GetParent();
  }
  return win;
}

wxCoord
wxWindowBase::AdjustForLayoutDirection( wxCoord x, wxCoord width, wxCoord widthTotal ) const {
  if( GetLayoutDirection() == wxLayout_RightToLeft ) {
    x = widthTotal - x - width;
  }
  return x;
}
